package com.sql.mysql.sharding.config;

import java.util.List;
import java.util.Set;

import com.sql.mysql.sharding.config.Range;
import com.sql.mysql.sharding.config.Shard;
import com.sql.mysql.sharding.config.ShardGroup;
import com.sql.mysql.sharding.config.Table;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ShardingConfigFind {

	public static void main(String[] args) {
		// Range[] ranges = new Range[] { new Range("1", "8"), new Range("8",
		// "10"), new Range("10", "12"),
		// new Range("60", "70") };
		// log.info("0 {}", inRanges(ranges, 0));
		// log.info("1 {}", inRanges(ranges, 1));
		// log.info("2 {}", inRanges(ranges, 2));
		// log.info("4 {}", inRanges(ranges, 4));
		// log.info("5 {}", inRanges(ranges, 5));
		// log.info("6 {}", inRanges(ranges, 6));
		// log.info("7 {}", inRanges(ranges, 7));
		// log.info("8 {}", inRanges(ranges, 8));
		// log.info("10 {}", inRanges(ranges, 10));
		// log.info("11 {}", inRanges(ranges, 11));
		// log.info("12 {}", inRanges(ranges, 12));
		// log.info("13 {}", inRanges(ranges, 13));
		// log.info("59 {}", inRanges(ranges, 59));
		// log.info("60 {}", inRanges(ranges, 60));
	}

	// 判断是不是某个key在一段range区间内
	public static boolean inRanges(List<Range> ranges, long key) {
		if (null == ranges) {
			return false;
		}
		// 只要找到1个,就算命中
		for (Range range : ranges) {
			if (range.in(key)) {
				return true;
			}
		}
		return false;
	}

	public static ShardGroup getShardGroup(long shardingKey, List<ShardGroup> shardGroups) {
		log.debug("try to get shard group");
		if (null == shardGroups) {
			return null;
		}
		log.debug("parameter shardGroups is valid {}", shardGroups.size());
		// 尝试找ShardGroup
		for (ShardGroup shardGroup : shardGroups) {
			log.debug("current shardGroup {} range {}", shardGroup.getName(), shardGroup.getRanges());
			if (inRanges(shardGroup.getRanges(), shardingKey)) {
				return shardGroup;
			}
		}
		log.debug("fail to find shardgroup for {}", shardingKey);
		return null;
	}

	@SuppressWarnings("rawtypes")
	public static Shard getShard(long shardingKey, List<ShardGroup> shardGroups) {
		// 参数校验
		if (null == shardGroups) {
			log.error("shardGroups parameter is null");
			return null;
		}
		// 保证找到ShardGroup
		ShardGroup targetShardGroup = getShardGroup(shardingKey, shardGroups);
		if (null == targetShardGroup) {
			log.error("fail to find shardgroup for {}", shardingKey);
			return null;
		}
		log.debug("succeed to get shardgroup {} ,param {}", targetShardGroup.getName(), targetShardGroup.getParam());
		// 求模
		int paramIntValue = Integer.parseInt(targetShardGroup.getParam());
		String modValue = "" + (shardingKey % paramIntValue);
		// 判断这个mod在哪个shard里
		List<Shard> shards = targetShardGroup.getShards();
		for (Shard shard : shards) {
			Set values = shard.getValues();
			if (null != values && values.contains(modValue)) {
				return shard;
			}
		}
		return null;// 到此已经可以拿到MasterSlaveDataSource了
	}

	public static Table getTable(long shardingKey, List<ShardGroup> shardGroups) {
		if (null == shardGroups) {
			return null;
		}
		Shard shard = getShard(shardingKey, shardGroups);
		if (null == shard) {
			log.error("fail to find shard for {}", shardingKey);
			return null;
		}
		log.debug("succeed to get shard {} ,values {} ", shard.getName(), shard.getValues());
		// 找到了shard
		List<Table> tables = shard.getTables();
		for (Table table : tables) {
			if (inRanges(table.getRanges(), shardingKey)) {
				return table;
			}
		}
		return null;
	}

}
